上一篇透過 VPC Peering,驗證了跨 VPC 通訊需要配合路由與 Security Group 設定。
網路連通之後,接下來要處理的是資料:應用程式產生的圖片、報表與上傳檔案,應該放在哪裡?
AWS 常見的選擇包括:
三個服務都能儲存資料,但應用程式使用它們的方式不同,選擇之前,比起先問「有多少 GB」,更重要的是:應用程式到底要怎麼讀寫這份資料?
假設有一個網站,會把使用者上傳的圖片寫進:
/uploads/product.jpg
只有一台 EC2 時,檔案存在這台主機的磁碟裡,看起來沒有問題。
但當網站擴展成兩台 EC2,放在 ALB 後面,就可能發生:
即使兩台 EC2 的網路互通,也不代表它們會自動共用檔案。
這時候,選型要回到應用程式的讀寫方式:
| 服務 | 儲存類型 | 應用程式如何存取 | 常見用途 |
|---|---|---|---|
| S3 | Object Storage(物件儲存) | 透過 API、SDK 或 HTTP 請求存取物件 | 圖片、影片、報表、備份 |
| EBS | Block Storage(區塊儲存) | 掛載到 EC2,由作業系統建立檔案系統後使用 | 系統磁碟、應用程式資料磁碟、自建資料庫 |
| EFS | File Storage(檔案儲存) | 透過 NFS 掛載,共用檔案與目錄 | 多台 Linux 主機共用上傳目錄或應用程式檔案 |
同樣是一張圖片,可以存在三種服務裡;真正不同的是,程式要怎麼取得它,以及誰負責維持資料的存取方式。
前面的跨帳號實作其實已經使用過 Amazon S3,例如:
aws s3api get-object \
--bucket shared-product-data-prod \
--key products/product.json \
/tmp/product.json
這個指令會向 S3 取得 Key 為 products/product.json 的 Object(物件),再下載到 EC2 的 /tmp/product.json,它並沒有把 S3 Bucket 掛載成主機上的磁碟。
在一般用途的 S3 Bucket 中,資料以 Object 儲存,每個物件透過 Object Key(物件鍵) 識別。例如:
images/products/product-001.jpg
在 S3 主控台中,這個名稱看起來像是 images 資料夾裡有一個 products 資料夾,再放入 product-001.jpg。
但對 S3 而言,images/products/product-001.jpg 整段才是完整的 Object Key ,其中的 images/ 與 images/products/ 是 Prefix(前綴),可以用來分類與列出物件,不是傳統檔案系統中真正的目錄。
這個差異會影響應用程式的寫法,原本把圖片存進 /uploads 的網站,改用 S3 後可以調整成:
images/products/product-001.jpg。如此一來,不論請求被分配到 EC2 A 還是 EC2 B,都能存取同一份物件,不必把圖片複製到每台主機,新增或替換 EC2 時,也不需要搬移這些上傳檔案。
商品圖片、影片、報表與備份等資料,都很適合從這種方式評估,如果應用程式可以使用物件 API,而且不需要共享檔案系統的操作方式,就可以優先考慮 S3。
但也會有需要承擔的責任,像是整合物件 API,並設計存取權限、版本保留與刪除規則等。
如果需求不是「存一個 Object」,而是應用程式需要主機上的磁碟,例如作業系統、套件安裝位置,或自建資料庫的資料目錄,就比較接近 Amazon EBS(Elastic Block Store)。
EBS 提供的是 Block Storage(區塊儲存),以 Linux 資料磁碟為例,通常需要:
/data 等路徑。之後應用程式就可以透過一般檔案操作讀寫資料,所以 EBS 比較像是提供 EC2 使用的持久化磁碟。
但有一個會直接影響架構的限制:EBS Volume 與使用它的 EC2,必須位於相同 AZ。
如果應用程式分散在兩個 AZ,就不能把其中一個 AZ 的 EBS Volume,直接掛到另一個 AZ 的 EC2 上使用。
EBS 也不適合直接拿來解決前面的「多台網站主機共用上傳目錄」問題。
雖然部分 io1、io2 Volume 支援 Multi-Attach(多重附加),可以同時附加到同一個 AZ 的多台 EC2,但這不代表它就變成一般的共享檔案系統,一般的 ext4、XFS 也並不是為多台主機同時寫入同一個 Volume 而設計的。
使用 EBS 時,也要規劃容量、IOPS、吞吐量與快照設定等,AWS 管理底層儲存設備,但檔案系統、應用程式資料一致性與復原流程,仍然需要自行處理。
如果既有程式就是要讀寫:
/uploads/product.jpg
而且短期內不方便改成 S3 API,這時可以評估 Amazon EFS(Elastic File System)。
EFS 提供的是共享 File Storage(檔案儲存),透過 NFS(Network File System,網路檔案系統) 讓多台 Linux EC2 可以掛載同一個 EFS、各台主機使用相同的目錄與檔案。
例如:
ALB
│
┌─────────┴─────────┐
▼ ▼
EC2 A EC2 B
│ │
└─────────┬─────────┘
▼
EFS
│
/shared/uploads
以前面的網站為例,兩台 EC2 都把同一個 EFS 掛載到 /uploads:
這能保留原本的檔案路徑操作方式,但使用前還是需要處理網路與權限。
EFS 透過 Mount Target(掛載目標) 提供 VPC 內的連線入口,Security Group 也必須允許用戶端存取 NFS 使用的 TCP 2049;掛載成功後,檔案與目錄的 POSIX 權限也會影響程式能否讀寫,網路能連上,不代表執行程式的使用者就有檔案寫入權限,這也跟我在前面網路篇一直有提到的概念十分相似。
另外,EFS 有兩種需要區分的檔案系統類型:
如果前面已經要求應用程式能承受單一 AZ 故障,我會選擇 Regional EFS,並在應用程式使用的 AZ 規劃掛載目標,而不會只看到「EFS」就假設所有配置都有相同的故障承受能力。
EFS 也不會自動解決所有並行寫入問題,如果兩個程式同時修改同一份檔案,仍然需要適當的鎖定或應用程式協調;既有程式改用網路檔案系統後,也應測試實際讀寫延遲,尤其是大量小檔案或頻繁開關檔案的工作負載。
回到最前面的網站,以下用一個假設情境比較。
網站目前有兩台跨 AZ 的 EC2,使用者上傳的圖片必須能被兩台主機讀取,乍看之下 S3 和 EFS 都可以解決「資料不要只存在 EC2 A」這件事,真正影響選擇的是 Application 怎麼使用這份資料。
| 條件 | 可優先選擇 | 需要承擔的管理責任 |
|---|---|---|
| 新開發的上傳功能,可以使用 SDK 存取物件 | S3 | 整合物件 API,設計授權與物件生命週期 |
既有程式必須讀寫 /uploads,多台主機需要共享 |
EFS Regional | 管理掛載、網路與檔案權限,驗證並行讀寫行為 |
| 資料只供單台 EC2 使用,需要主機磁碟介面 | EBS | 規劃容量與效能,管理檔案系統、快照與復原 |
如果這是可以調整程式的新功能,那可以優先選擇 S3,讓上傳資料不依附任何一台 EC2。
在「多台應用程式需要存取相同圖片,而且程式可以使用物件 API」的條件下,我會優先選擇 S3,讓各台主機透過相同的物件位置讀寫資料;同時就需要接受應用程式需要整合 API、存取授權與物件管理流程的責任。
但如果是短期內不能修改的既有系統,則可以改選 EFS Regional,保留共享目錄的操作方式。
EBS 在這個跨 AZ 共享上傳目錄的需求中,就不是合適的選項:它的掛載範圍與共享方式,都不符合這次要解決的問題。
三個服務也可以同時出現在一套系統裡,例如 EC2 用 EBS 作為系統磁碟,上傳圖片放在 S3,少數必須共享檔案路徑的元件使用 EFS,選擇的單位應該是資料用途,而不是替整個系統只選一種儲存服務。
最後還要接回 Day 17:資料能被多台主機存取,或儲存在多個 AZ,不代表誤刪之後一定救得回來。 版本保留、備份與還原演練,仍然要依資料的重要程度另外規劃。
今天從物件、區塊與共享檔案的存取方式,選擇適合的儲存服務。
但訂單、會員與庫存資料,除了保存之外,還需要查詢、更新與交易處理,下一篇會比較 Amazon RDS、Amazon Aurora 與 Amazon DynamoDB,看看資料模型與查詢方式,如何影響資料庫的選擇。